{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `logictools` WaveDrom Tutorial\n",
    "[WaveDrom](http://wavedrom.com) is a tool for rendering digital timing waveforms. The waveforms are defined in a simple textual format.   \n",
    "This notebook will show how to render digital waveforms using the pynq library.\n",
    "\n",
    "The __`logictools`__ overlay uses the same format as WaveDrom to specify and generate real signals on the board.\n",
    "\n",
    "A full tutorial of WaveDrom can be found [here](http://wavedrom.com/tutorial.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Step 1: Import the `draw_wavedrom()` method from the pynq library"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from pynq.lib.logictools.waveform import draw_wavedrom"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A simple function to add wavedrom diagrams into an jupyter notebook. It utilises the wavedrom java script library.  \n",
    "\n",
    "<font color=\"DodgerBlue\">**Example usage:**</font> \n",
    "```python\n",
    "        from pynq.lib.logictools.waveform import draw_wavedrom   \n",
    "        \n",
    "        clock = {'signal': [{'name': 'clk', 'wave': 'h....l...'}]}   \n",
    "        draw_wavedrom(clock)   \n",
    "```       \n",
    "<font color=\"DodgerBlue\">**Method:**</font> \n",
    "```python\n",
    "        def draw_wavedrom(data, width=None):            \n",
    "        # Note the optional argument width forces the width in pixels\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Step 2: Specify and render a waveform"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div class=\"output_svg\"><img class=\"svg\" style=\"max-width: none\"src=\"\" alt=\"Image\"></img></div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "clock = {'signal': [{'name': 'clock_0', 'wave': 'hlhlhlhlhlhlhlhl'}],\n",
    "         'foot': {'tock': 1},\n",
    "         'head': {'text': 'Clock Signal'}}\n",
    "\n",
    "draw_wavedrom(clock)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Notes on waveform specification__\n",
    "\n",
    "![](./images/waveform_spec_format0.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Step 3: Adding more signals to the waveform"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div class=\"output_svg\"><img class=\"svg\" style=\"max-width: none\"src=\"\" alt=\"Image\"></img></div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "pattern = {'signal': [{'name': 'clk', 'wave': 'hl' * 8},\n",
    "                      {'name': 'clkn', 'wave': 'lh' * 8},\n",
    "                      {'name': 'data0', 'wave': 'l.......h.......'},\n",
    "                      {'name': 'data1', 'wave': 'h.l...h...l.....'}],\n",
    "           'foot': {'tock': 1},\n",
    "           'head': {'text': 'Pattern'}}\n",
    "\n",
    "draw_wavedrom(pattern)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Notes on waveform specification__\n",
    "\n",
    "![](./images/waveform_spec_format1.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Adding multiple wave groups and spaces__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div class=\"output_svg\"><img class=\"svg\" style=\"max-width: none\"src=\"\" alt=\"Image\"></img></div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "pattern_group = {'signal': [['Group1',\n",
    "                             {'name': 'clk', 'wave': 'hl' * 8},\n",
    "                             {'name': 'clkn', 'wave': 'lh' * 8},\n",
    "                             {'name': 'data0', 'wave': 'l.......h.......'},\n",
    "                             {'name': 'data1', 'wave': 'h.l...h...l.....'}],\n",
    "                            {},\n",
    "                            ['Group2',\n",
    "                             {'name': 'data2', 'wave': 'l...h..l.h......'},\n",
    "                             {'name': 'data3', 'wave': 'l.h.' * 4}]],\n",
    "                 'foot': {'tock': 1},\n",
    "                 'head': {'text': 'Pattern'}}\n",
    "\n",
    "draw_wavedrom(pattern_group)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Notes on waveform specification__\n",
    "\n",
    "![](./images/waveform_spec_format2.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# WaveDrom for real-time pattern generation and trace analysis"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### The __`logictools`__ overlay uses WaveJSON format to specify and generate real signals on the board.\n",
    "\n",
    "![](./images/logictools_block_diagram.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* As shown in the figure above, the Pattern Generator is an output-only block that specifies a sequence of logic values (patterns) which appear on the output pins of the ARDUINO interface. The logictools API for Pattern Generator accepts **WaveDrom** specification syntax with some enhancements.\n",
    "   \n",
    "   \n",
    "* The Trace Analyzer is an input-only block that captures and records all the IO signals. These signals may be outputs driven by the generators or inputs to the PL that are driven by external circuits. The Trace Analyzer allows us to verify that the output signals we have specified from the generators are being applied correctly. It also allows us to debug and analyze the opearion of the external interface. \n",
    "   \n",
    "   \n",
    "* The signals generated or captured by both the blocks can be displayed in the notebook by populating the WaveJSON dictionary that we have seen in this notebook. Users can access this dictionary through the provided API to extend or modify the waveform with special annotations.\n",
    "   \n",
    "   \n",
    "* we use a subset of the wave tokens that are allowed by WaveDrom to specify the waveforms for the Pattern Generator. However, users can call the `draw_waveform()` method on the dictionary populated by the Trace Analyzer to extend and modify the dictionary with annotations.\n",
    "   \n",
    "   \n",
    "__In the example below, we are going to generate 3 signals on the Arduino interface pins D0, D1 and D2 using the Pattern Generator. Since all IOs are accessible to the Trace analyzer, we will capture the data on the pins as well. This operation will serve as an internal loopback. __\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Step 1: Download the `logictools` overlay and specify the pattern\n",
    "The pattern to be generated is specified in the waveJSON format. The Waveform class is used to display the specified waveform."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div class=\"output_svg\"><img class=\"svg\" style=\"max-width: none\"src=\"\" alt=\"Image\"></img></div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from pynq.lib.logictools import Waveform\n",
    "from pynq.overlays.logictools import LogicToolsOverlay\n",
    "\n",
    "logictools_olay = LogicToolsOverlay('logictools.bit')\n",
    "\n",
    "loopback_test = {'signal': [\n",
    "    ['stimulus',\n",
    "     {'name': 'output0', 'pin': 'D0', 'wave': 'lh' * 8},\n",
    "     {'name': 'output1', 'pin': 'D1', 'wave': 'l.h.' * 4},\n",
    "     {'name': 'output2', 'pin': 'D2', 'wave': 'l...h...' * 2}],\n",
    "    {},\n",
    "    ['analysis',\n",
    "     {'name': 'input0', 'pin': 'D0'},\n",
    "     {'name': 'input1', 'pin': 'D1'},\n",
    "     {'name': 'input2', 'pin': 'D2'}]],\n",
    "\n",
    "    'foot': {'tock': 1},\n",
    "    'head': {'text': 'loopback_test'}}\n",
    "\n",
    "waveform = Waveform(loopback_test)\n",
    "waveform.display()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Note:** Since there are no captured samples at this moment, the analysis group will be empty."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Notes on the enhanced WaveJSON specification format__\n",
    "\n",
    "\n",
    "![](./images/waveform_spec_format3.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Step 2: Run the pattern generator and trace the loopback signals.\n",
    "This step populates the WaveJSON dict with the captured trace analyzer samples. The dict can now serve as an ouput that we can further modify. It is shown in the next step."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div class=\"output_svg\"><img class=\"svg\" style=\"max-width: none\"src=\"\" alt=\"Image\"></img></div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "pattern_generator = logictools_olay.pattern_generator\n",
    "\n",
    "pattern_generator.trace(num_analyzer_samples=16)\n",
    "pattern_generator.setup(loopback_test,\n",
    "                        stimulus_group_name='stimulus',\n",
    "                        analysis_group_name='analysis')\n",
    "\n",
    "pattern_generator.run()\n",
    "pattern_generator.show_waveform()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Step 3: View the output waveJSON dict."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'foot': {'tock': 1},\n",
      " 'head': {'text': 'loopback_test'},\n",
      " 'signal': [['stimulus',\n",
      "             {'name': 'output0', 'pin': 'D0', 'wave': 'lhlhlhlhlhlhlhlh'},\n",
      "             {'name': 'output1', 'pin': 'D1', 'wave': 'l.h.l.h.l.h.l.h.'},\n",
      "             {'name': 'output2', 'pin': 'D2', 'wave': 'l...h...l...h...'}],\n",
      "            {},\n",
      "            ['analysis',\n",
      "             {'name': 'input0', 'pin': 'D0', 'wave': 'lhlhlhlhlhlhlhlh'},\n",
      "             {'name': 'input1', 'pin': 'D1', 'wave': 'l.h.l.h.l.h.l.h.'},\n",
      "             {'name': 'input2', 'pin': 'D2', 'wave': 'l...h...l...h...'}]]}\n"
     ]
    }
   ],
   "source": [
    "import pprint\n",
    "\n",
    "output_wavejson = pattern_generator.waveform.waveform_dict\n",
    "pprint.pprint(output_wavejson)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](./images/waveform_output_dictionary.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "### Step 4: Extending the output waveJSON dict with state annotation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "state_list = ['S0', 'S1', 'S2', 'S3', 'S4', 'S5', 'S6', 'S7',\n",
    "              'S0', 'S1', 'S2', 'S3', 'S4', 'S5', 'S6', 'S7']\n",
    "\n",
    "color_dict = {'white': '2', 'yellow': '3', 'orange': '4', 'blue': '5'}\n",
    "\n",
    "output_wavejson['signal'].extend([{}, ['Annotation',\n",
    "                                       {'name': 'state',\n",
    "                                        'wave': color_dict['yellow'] * 8 +\n",
    "                                                color_dict['blue'] * 8,\n",
    "                                        'data': state_list}]])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Note: __ The color_dict is a color code map as defined by WaveDrom"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div class=\"output_svg\"><img class=\"svg\" style=\"max-width: none\"src=\"\" alt=\"Image\"></img></div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "draw_wavedrom(output_wavejson)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
